# weather_tools.py

"""
天气查询工具模块，提供天气查询功能。
这个模块只包含工具函数，不包含MCP服务器实例。
"""

import sys
import re
import json
from urllib.parse import quote
from bs4 import BeautifulSoup
from fake_useragent import UserAgent
import httpx
import datetime

# --- 日志文件写入函数 ---
def write_log(level: str, message: str, city: str):
    """将详细日志写入本地文件 mcp_server_log.txt"""
    timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    log_entry = f"[{timestamp}] [{level}] [City: {city}] {message}\n"
    try:
        # 使用追加模式 'a' 写入日志文件
        with open("mcp_server_log.txt", "a", encoding="utf-8") as f:
            f.write(log_entry)
    except Exception as e:
        # 如果文件写入失败，作为最后手段仍输出到 stderr
        sys.stderr.write(f"FATAL: Could not write to log file: {e}\n")

# --- 天气查询工具函数 ---
async def parse_weather(city: str, days: int = 1) -> str:
    """
    天气查询工具: 专门用于查询指定城市的天气信息，返回指定天数的天气预报。
    注意：只有在用户明确询问天气、温度、降雨等天气相关信息时才使用此工具。
    
    Args:
        city: 要查询天气的城市名称 (例如: 成都、北京、上海)
        days: 查询天数，范围1-14天，默认为1天
    """
    # 限制查询天数范围
    days = max(1, min(14, days))
    
    # 动态生成User-Agent
    headers = {
        'User-Agent': UserAgent().chrome,
        'Referer': 'https://www.baidu.com/link?'
    }

    try:
        write_log("DEBUG", f"尝试发起天气查询请求，查询{days}天", city)

        # 构造请求URL
        encoded_city = quote(f"{city}天气")
        url = f"https://weathernew.pae.baidu.com/weathernew/pc?query={encoded_city}&srcid=4982&forecast=long_day_forecast"

        # 异步请求天气数据
        async with httpx.AsyncClient() as client:
            response = await client.get(url, headers=headers, timeout=15.0)
            response.raise_for_status()

        # 解析HTML中的JSON数据
        soup = BeautifulSoup(response.text, 'lxml')
        script_tag = soup.find('script')
        
        if not script_tag:
            write_log("ERROR", "解析失败：未在HTML中找到 script 标签。", city)
            return f"解析失败：未在HTML中找到 script 标签。"
            
        match = re.search(r'window\.tplData\s*=\s*({.*})', script_tag.get_text(), re.DOTALL)
        
        if not match:
            write_log("ERROR", "解析失败：未找到天气数据。", city)
            return "解析失败：未找到天气数据。"

        # 解析JSON数据
        data_json = json.loads(match.group(1))
        forecast_data = data_json.get("long_day_forecast", {}).get("info", [])
        
        if not forecast_data:
            write_log("ERROR", f"未能获取到 {city} 的天气预报数据。", city)
            return f"未能获取到 {city} 的天气预报数据。"

        # 限制显示天数
        display_count = min(days, len(forecast_data))
        result_str = ""
        
        for i in range(display_count):
            data = forecast_data[i]
            
            # 标记今日和预测
            date_label = "今日" if i == 0 else "预测"
            
            # 获取天气状况
            weather_condition = data.get('weather_day') or data.get('weather') or "N/A"
            
            # 获取温度范围
            temp_min = data.get('temperature_night', 'N/A')
            temp_max = data.get('temperature_day', 'N/A')
            temperature = f"{temp_min}°C~{temp_max}°C"
            
            # 获取PM2.5数据
            pm25 = data.get("pm25", {}).get('listQuality', {}).get('listValue', "N/A")
            
            result_str += (
                f"[{date_label}]\n"
                f"日期: {data.get('date', 'N/A')}\n"
                f"天气状况: {weather_condition}\n"
                f"温度: {temperature}\n"
                f"日出: {data.get('sunriseTime', 'N/A')}\n"
                f"日落: {data.get('sunsetTime', 'N/A')}\n"
                f"PM2.5: {pm25}\n\n"
            )
        
        write_log("INFO", f"成功获取并解析数据，共{display_count}天", city)
        return result_str

    # 错误处理部分：记录详细日志
    except httpx.HTTPStatusError as e:
        error_msg = f"天气查询失败：HTTP错误状态码 {e.response.status_code}。"
        write_log("ERROR", error_msg, city)
        return error_msg
    except httpx.RequestError as e:
        error_msg = f"天气查询失败：网络请求错误或超时。"
        write_log("ERROR", error_msg, city)
        return error_msg
    except (json.JSONDecodeError, KeyError, TypeError) as e:
        error_msg = f"天气查询失败：数据解析错误（目标网站结构可能已变化，错误类型: {type(e).__name__}）。"
        write_log("ERROR", error_msg, city)
        return error_msg
    except Exception as e:
        error_msg = f"服务器内部未预料的错误：{str(e)}"
        write_log("FATAL", error_msg, city)
        return error_msg


# MCP服务器实现
if __name__ == "__main__":
    from mcp.server.fastmcp import FastMCP
    
    # 创建MCP服务器
    mcp = FastMCP("weather-server")
    
    @mcp.tool()
    async def weather_query(city: str, days: int = 1) -> str:
        """
        天气查询工具: 专门用于查询指定城市的天气信息，返回指定天数的天气预报。
        注意：只有在用户明确询问天气、温度、降雨等天气相关信息时才使用此工具。
        
        Args:
            city: 要查询天气的城市名称 (例如: 成都、北京、上海)
            days: 查询天数，范围1-14天，默认为1天
        """
        return await parse_weather(city, days)
    
    # 运行服务器
    mcp.run(transport='stdio')